home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / BIND.C < prev    next >
C/C++ Source or Header  |  1993-04-22  |  24KB  |  1,057 lines

  1. /*    This file is for functions having to do with key bindings,
  2.     descriptions, help commands and startup file.
  3.  
  4.     written 11-feb-86 by Daniel Lawrence
  5.                                 */
  6.  
  7. #include    <stdio.h>
  8. #include    "estruct.h"
  9. #include    "eproto.h"
  10. #include    "edef.h"
  11. #include    "elang.h"
  12. #include    "epath.h"
  13.  
  14. PASCAL NEAR help(f, n)    /* give me some help!!!!
  15.            bring up a fake buffer and read the help file
  16.            into it with view mode            */
  17.  
  18. int f,n;    /* prefix flag and argument */
  19.  
  20. {
  21.     register BUFFER *bp;    /* buffer pointer to help */
  22.     char *fname;        /* file name of help file */
  23.  
  24.     /* first check if we are already here */
  25.     bp = bfind("emacs.hlp", FALSE, BFINVS);
  26.  
  27.     if (bp == NULL) {
  28. #if SHARED
  29.         strcpy(tname, pathname[1]);
  30.         fname = flook(tname, FALSE);
  31. #else        
  32.         fname = flook(pathname[1], FALSE);
  33. #endif
  34.         if (fname == NULL) {
  35.             mlwrite(TEXT12);
  36. /*                "[Help file is not online]" */
  37.             return(FALSE);
  38.         }
  39.     }
  40.  
  41.     /* split the current window to make room for the help stuff */
  42.     if (splitwind(FALSE, 1) == FALSE)
  43.             return(FALSE);
  44.  
  45.     if (bp == NULL) {
  46.         /* and read the stuff in */
  47.         if (getfile(fname, FALSE) == FALSE)
  48.             return(FALSE);
  49.     } else
  50.         swbuffer(bp);
  51.  
  52.     /* make this window in VIEW mode, update all mode lines */
  53.     curwp->w_bufp->b_mode |= MDVIEW;
  54.     curwp->w_bufp->b_flag |= BFINVS;
  55.     upmode();
  56.     return(TRUE);
  57. }
  58.  
  59. PASCAL NEAR deskey(f, n)    /* describe the command for a certain key */
  60.  
  61. int f,n;    /* prefix flag and argument */
  62.  
  63. {
  64.     register int c;     /* key to describe */
  65.     register char *ptr;    /* string pointer to scan output strings */
  66.     char outseq[NSTRING];    /* output buffer for command sequence */
  67.  
  68.     /* prompt the user to type us a key to describe */
  69.     mlwrite(TEXT13);
  70. /*        ": describe-key " */
  71.  
  72.     /* get the command sequence to describe
  73.        change it to something we can print as well */
  74.     /* and dump it out */
  75.     ostring(cmdstr(c = getckey(FALSE), &outseq[0]));
  76.     ostring(" ");
  77.  
  78.     /* find the right ->function */
  79.     if ((ptr = getfname(getbind(c))) == NULL)
  80.         ptr = "Not Bound";
  81.  
  82.     /* output the command sequence */
  83.     ostring(ptr);
  84.     return(TRUE);
  85. }
  86.  
  87. /* bindtokey:    add a new key to the key binding table        */
  88.  
  89. PASCAL NEAR bindtokey(f, n)
  90.  
  91. int f, n;    /* command arguments [IGNORED] */
  92.  
  93. {
  94.     register unsigned int c;/* command key to bind */
  95.     register int (PASCAL NEAR *kfunc)();/* ptr to the requested function to bind to */
  96.     register KEYTAB *ktp;    /* pointer into the command table */
  97.     register int found;    /* matched command flag */
  98.     char outseq[80];    /* output buffer for keystroke sequence */
  99.  
  100.     /* prompt the user to type in a key to bind */
  101.     /* get the function name to bind it to */
  102.     kfunc = getname(TEXT15);
  103. /*            ": bind-to-key " */
  104.     if (kfunc == NULL) {
  105.         mlwrite(TEXT16);
  106. /*            "[No such function]" */
  107.         return(FALSE);
  108.     }
  109.     if (clexec == FALSE) {
  110.         ostring(" ");
  111.         TTflush();
  112.     }
  113.  
  114.     /* get the command sequence to bind */
  115.     c = getckey((kfunc == meta) || (kfunc == cex) ||
  116.             (kfunc == unarg) || (kfunc == ctrlg));
  117.  
  118.     if (clexec == FALSE) {
  119.  
  120.         /* change it to something we can print as well */
  121.         /* and dump it out */
  122.         ostring(cmdstr(c, &outseq[0]));
  123.     }
  124.  
  125.     /* if the function is a unique prefix key */
  126.     if (kfunc == unarg || kfunc == ctrlg || kfunc == quote) {
  127.  
  128.         /* search for an existing binding for the prefix key */
  129.         ktp = &keytab[0];
  130.         while (ktp->k_type != BINDNUL) {
  131.             if (ktp->k_type == BINDFNC && ktp->k_ptr.fp == kfunc)
  132.                 unbindchar(ktp->k_code);
  133.             ++ktp;
  134.         }
  135.  
  136.         /* reset the appropriate global prefix variable */
  137.         if (kfunc == unarg)
  138.             reptc = c;
  139.         if (kfunc == ctrlg)
  140.             abortc = c;
  141.         if (kfunc == quote)
  142.             quotec = c;
  143.     }
  144.  
  145.     /* search the table to see if it exists */
  146.     ktp = &keytab[0];
  147.     found = FALSE;
  148.     while (ktp->k_type != BINDNUL) {
  149.         if (ktp->k_code == c) {
  150.             found = TRUE;
  151.             break;
  152.         }
  153.         ++ktp;
  154.     }
  155.  
  156.     if (found) {    /* it exists, just change it then */
  157.         ktp->k_ptr.fp = kfunc;
  158.         ktp->k_type = BINDFNC;
  159.     } else {    /* otherwise we need to add it to the end */
  160.         /* if we run out of binding room, bitch */
  161.         if (ktp >= &keytab[NBINDS]) {
  162.             mlwrite(TEXT17);
  163. /*                "Binding table FULL!" */
  164.             return(FALSE);
  165.         }
  166.  
  167.         ktp->k_code = c;    /* add keycode */
  168.         ktp->k_ptr.fp = kfunc;    /* and the function pointer */
  169.         ktp->k_type = BINDFNC;    /* and the binding type */
  170.         ++ktp;            /* and make sure the next is null */
  171.         ktp->k_code = 0;
  172.         ktp->k_type = BINDNUL;
  173.         ktp->k_ptr.fp = NULL;
  174.     }
  175.  
  176.     /* if we have rebound the meta key, make the
  177.        search terminators follow it            */
  178.     if (kfunc == meta) {
  179.         sterm = c;
  180.         isterm = c;
  181.     }
  182.  
  183.     return(TRUE);
  184. }
  185.  
  186. /* macrotokey:    Bind a key to a macro in the key binding table */
  187.  
  188. PASCAL NEAR macrotokey(f, n)
  189.  
  190. int f, n;    /* command arguments [IGNORED] */
  191.  
  192. {
  193.     register unsigned int c;/* command key to bind */
  194.     register BUFFER *kmacro;/* ptr to buffer of macro to bind to key */
  195.     register KEYTAB *ktp;    /* pointer into the command table */
  196.     register int found;    /* matched command flag */
  197.     register int status;    /* error return */
  198.     char outseq[80];    /* output buffer for keystroke sequence */
  199.     char bufn[NBUFN];    /* buffer to hold macro name */
  200.  
  201.     /* get the buffer name to use */
  202.     if ((status=mlreply(TEXT215, &bufn[1], NBUFN-2)) != TRUE)
  203. /*        ": macro-to-key " */
  204.         return(status);
  205.  
  206.     /* build the responce string for later */
  207.     strcpy(outseq, TEXT215);
  208. /*           ": macro-to-key " */
  209.     strcat(outseq, &bufn[1]);
  210.  
  211.     /* translate it to a buffer pointer */
  212.     bufn[0] = '[';
  213.     strcat(bufn, "]");
  214.     if ((kmacro=bfind(bufn, FALSE, 0)) == NULL) {
  215.         mlwrite(TEXT130);
  216. /*        "Macro not defined"*/
  217.         return(FALSE);
  218.     }
  219.  
  220.     strcat(outseq, " ");
  221.     mlwrite(outseq);
  222.  
  223.     /* get the command sequence to bind */
  224.     c = getckey(FALSE);
  225.  
  226.     /* change it to something we can print as well */
  227.     /* and dump it out */
  228.     ostring(cmdstr(c, &outseq[0]));
  229.  
  230.     /* search the table to see if it exists */
  231.     ktp = &keytab[0];
  232.     found = FALSE;
  233.     while (ktp->k_type != BINDNUL) {
  234.         if (ktp->k_code == c) {
  235.             found = TRUE;
  236.             break;
  237.         }
  238.         ++ktp;
  239.     }
  240.  
  241.     if (found) {    /* it exists, just change it then */
  242.         ktp->k_ptr.buf = kmacro;
  243.         ktp->k_type = BINDBUF;
  244.     } else {    /* otherwise we need to add it to the end */
  245.         /* if we run out of binding room, bitch */
  246.         if (ktp >= &keytab[NBINDS]) {
  247.             mlwrite(TEXT17);
  248. /*                "Binding table FULL!" */
  249.             return(FALSE);
  250.         }
  251.  
  252.         ktp->k_code = c;    /* add keycode */
  253.         ktp->k_ptr.buf = kmacro;    /* and the function pointer */
  254.         ktp->k_type = BINDBUF;    /* and the binding type */
  255.         ++ktp;            /* and make sure the next is null */
  256.         ktp->k_code = 0;
  257.         ktp->k_type = BINDNUL;
  258.         ktp->k_ptr.fp = NULL;
  259.     }
  260.  
  261.     return(TRUE);
  262. }
  263.  
  264. /* unbindkey:    delete a key from the key binding table */
  265.  
  266. PASCAL NEAR unbindkey(f, n)
  267.  
  268. int f, n;    /* command arguments [IGNORED] */
  269.  
  270. {
  271.     register int c;     /* command key to unbind */
  272.     char outseq[80];    /* output buffer for keystroke sequence */
  273.  
  274.     /* prompt the user to type in a key to unbind */
  275.     mlwrite(TEXT18);
  276. /*        ": unbind-key " */
  277.  
  278.     /* get the command sequence to unbind */
  279.     c = getckey(FALSE);        /* get a command sequence */
  280.  
  281.     /* change it to something we can print as well */
  282.     /* and dump it out */
  283.     ostring(cmdstr(c, &outseq[0]));
  284.  
  285.     /* if it isn't bound, bitch */
  286.     if (unbindchar(c) == FALSE) {
  287.         mlwrite(TEXT19);
  288. /*            "[Key not bound]" */
  289.         return(FALSE);
  290.     }
  291.     return(TRUE);
  292. }
  293.  
  294. PASCAL NEAR unbindchar(c)
  295.  
  296. int c;        /* command key to unbind */
  297.  
  298. {
  299.     register KEYTAB *ktp;    /* pointer into the command table */
  300.     register KEYTAB *sktp;    /* saved pointer into the command table */
  301.     register int found;    /* matched command flag */
  302.  
  303.     /* search the table to see if the key exists */
  304.     ktp = &keytab[0];
  305.     found = FALSE;
  306.     while (ktp->k_type != BINDNUL) {
  307.         if (ktp->k_code == c) {
  308.             found = TRUE;
  309.             break;
  310.         }
  311.         ++ktp;
  312.     }
  313.  
  314.     /* if it isn't bound, bitch */
  315.     if (!found)
  316.         return(FALSE);
  317.  
  318.     /* save the pointer and scan to the end of the table */
  319.     sktp = ktp;
  320.     while (ktp->k_type != BINDNUL)
  321.         ++ktp;
  322.     --ktp;        /* backup to the last legit entry */
  323.  
  324.     /* copy the last entry to the current one */
  325.     sktp->k_code = ktp->k_code;
  326.     sktp->k_type = ktp->k_type;
  327.     if (sktp->k_type == BINDFNC)
  328.         sktp->k_ptr.fp     = ktp->k_ptr.fp;
  329.     else if (sktp->k_type == BINDBUF)
  330.         sktp->k_ptr.buf   = ktp->k_ptr.buf;
  331.  
  332.     /* null out the last one */
  333.     ktp->k_code = 0;
  334.     ktp->k_type = BINDNUL;
  335.     ktp->k_ptr.fp = NULL;
  336.     return(TRUE);
  337. }
  338.  
  339. /* Describe bindings:
  340.  
  341.        bring up a fake buffer and list the key bindings
  342.        into it with view mode
  343. */
  344.  
  345. PASCAL NEAR desbind(f, n)
  346.  
  347. int f,n;    /* prefix flag and argument */
  348.  
  349. {
  350.     return(buildlist(TRUE, ""));
  351. }
  352.  
  353. PASCAL NEAR apro(f, n)    /* Apropos (List functions that match a substring) */
  354.  
  355. int f,n;    /* prefix flag and argument */
  356.  
  357. {
  358.     char mstring[NSTRING];    /* string to match cmd names to */
  359.     int status;        /* status return */
  360.  
  361.     status = mlreply(TEXT20, mstring, NSTRING - 1);
  362. /*             "Apropos string: " */
  363.     if (status != TRUE)
  364.         return(status);
  365.  
  366.     return(buildlist(FALSE, mstring));
  367. }
  368.  
  369. PASCAL NEAR buildlist(type, mstring)  /* build a binding list (limited or full) */
  370.  
  371. int type;    /* true = full list,   false = partial list */
  372. char *mstring;    /* match string if a partial list */
  373.  
  374. {
  375.     register KEYTAB *ktp;    /* pointer into the command table */
  376.     register NBIND *nptr;    /* pointer into the name binding table */
  377.     register BUFFER *listbuf;/* buffer to put binding list into */
  378.     register BUFFER *bp;    /* buffer ptr for function scan */
  379.     int cpos;        /* current position to use in outseq */
  380.     char outseq[80];    /* output buffer for keystroke sequence */
  381.  
  382.     /* get a buffer for the binding list */
  383.     listbuf = bfind(TEXT21, TRUE, BFINVS);
  384. /*           "Binding list" */
  385.     if (listbuf == NULL || bclear(listbuf) == FALSE) {
  386.         mlwrite(TEXT22);
  387. /*            "Can not display binding list" */
  388.         return(FALSE);
  389.     }
  390.  
  391.     /* let us know this is in progress */
  392.     mlwrite(TEXT23);
  393. /*        "[Building binding list]" */
  394.  
  395.     /* build the contents of this window, inserting it line by line */
  396.     nptr = &names[0];
  397.     while (nptr->n_func != NULL) {
  398.  
  399.         /* add in the command name */
  400.         strcpy(outseq, nptr->n_name);
  401.         cpos = strlen(outseq);
  402.  
  403.         /* if we are executing an apropos command..... */
  404.         if (type == FALSE &&
  405.             /* and current string doesn't include the search string */
  406.             strinc(outseq, mstring) == FALSE)
  407.             goto fail;
  408.  
  409.         /* search down any keys bound to this */
  410.         ktp = &keytab[0];
  411.         while (ktp->k_type != BINDNUL) {
  412.             if (ktp->k_type == BINDFNC &&
  413.                 ktp->k_ptr.fp == nptr->n_func) {
  414.                 /* padd out some spaces */
  415.                 while (cpos < 25)
  416.                     outseq[cpos++] = ' ';
  417.  
  418.                 /* add in the command sequence */
  419.                 cmdstr(ktp->k_code, &outseq[cpos]);
  420.  
  421.                 /* and add it as a line into the buffer */
  422.                 if (addline(listbuf, outseq) != TRUE)
  423.                     return(FALSE);
  424.  
  425.                 cpos = 0;    /* and clear the line */
  426.             }
  427.             ++ktp;
  428.         }
  429.  
  430.         /* if no key was bound, we need to dump it anyway */
  431.         if (cpos > 0) {
  432.             outseq[cpos] = 0;
  433.             if (addline(listbuf, outseq) != TRUE)
  434.                 return(FALSE);
  435.         }
  436.  
  437. fail:        /* and on to the next name */
  438.         ++nptr;
  439.     }
  440.  
  441.     /* add a blank line between the key and macro lists */
  442.     if (addline(listbuf, "") != TRUE)
  443.         return(FALSE);
  444.  
  445.     /* scan all buffers looking for macroes and their bindings */
  446.     bp = bheadp;
  447.     while (bp) {
  448.  
  449.         /* is this buffer a macro? */
  450.         if (bp->b_bname[0] != '[')
  451.             goto bfail;
  452.  
  453.         /* add in the command name */
  454.         strcpy(outseq, bp->b_bname);
  455.         cpos = strlen(outseq);
  456.  
  457.         /* if we are executing an apropos command..... */
  458.         if (type == FALSE &&
  459.             /* and current string doesn't include the search string */
  460.             strinc(outseq, mstring) == FALSE)
  461.             goto bfail;
  462.  
  463.         /* search down any keys bound to this macro */
  464.         ktp = &keytab[0];
  465.         while (ktp->k_type != BINDNUL) {
  466.             if (ktp->k_type == BINDBUF &&
  467.                 ktp->k_ptr.buf == bp) {
  468.                 /* padd out some spaces */
  469.                 while (cpos < 25)
  470.                     outseq[cpos++] = ' ';
  471.  
  472.                 /* add in the command sequence */
  473.                 cmdstr(ktp->k_code, &outseq[cpos]);
  474.  
  475.                 /* and add it as a line into the buffer */
  476.                 if (addline(listbuf, outseq) != TRUE)
  477.                     return(FALSE);
  478.  
  479.                 cpos = 0;    /* and clear the line */
  480.             }
  481.             ++ktp;
  482.         }
  483.  
  484.         /* if no key was bound, we need to dump it anyway */
  485.         if (cpos > 0) {
  486.             outseq[cpos] = 0;
  487.             if (addline(listbuf, outseq) != TRUE)
  488.                 return(FALSE);
  489.         }
  490.  
  491. bfail:        /* and on to the next buffer */
  492.         bp = bp->b_bufp;
  493.     }
  494.  
  495.     wpopup(listbuf);
  496.     mlerase();    /* clear the mode line */
  497.     return(TRUE);
  498. }
  499.  
  500. PASCAL NEAR strinc(source, sub) /* does source include sub? */
  501.  
  502. char *source;    /* string to search in */
  503. char *sub;    /* substring to look for */
  504.  
  505. {
  506.     char *sp;    /* ptr into source */
  507.     char *nxtsp;    /* next ptr into source */
  508.     char *tp;    /* ptr into substring */
  509.  
  510.     /* for each character in the source string */
  511.     sp = source;
  512.     while (*sp) {
  513.         tp = sub;
  514.         nxtsp = sp;
  515.  
  516.         /* is the substring here? */
  517.         while (*tp) {
  518.             if (*nxtsp++ != *tp)
  519.                 break;
  520.             else
  521.                 tp++;
  522.         }
  523.  
  524.         /* yes, return a success */
  525.         if (*tp == 0)
  526.             return(TRUE);
  527.  
  528.         /* no, onward */
  529.         sp++;
  530.     }
  531.     return(FALSE);
  532. }
  533.  
  534. /* get a command key sequence from the keyboard */
  535.  
  536. unsigned int PASCAL NEAR getckey(mflag)
  537.  
  538. int mflag;    /* going for a meta sequence? */
  539.  
  540. {
  541.     register unsigned int c;    /* character fetched */
  542.     char tok[NSTRING];        /* command incoming */
  543.  
  544.     /* check to see if we are executing a command line */
  545.     if (clexec) {
  546.         macarg(tok);    /* get the next token */
  547.         return(stock(tok));
  548.     }
  549.  
  550.     /* or the normal way */
  551.     if (mflag)
  552.         c = getkey();
  553.     else
  554.         c = getcmd();
  555.     return(c);
  556. }
  557.  
  558. /* execute the startup file */
  559.  
  560. PASCAL NEAR startup(sfname)
  561.  
  562. char *sfname;    /* name of startup file (null if default) */
  563.  
  564. {
  565.     char *fname;    /* resulting file name to execute */
  566.     char name[NSTRING];    /* name with extention */
  567.  
  568.     /* look up the startup file */
  569.     if (*sfname != 0) {
  570.  
  571.          /* default the extention */
  572.         strcpy(name, sfname);
  573.         if (sindex(name, ".") == 0)
  574.             strcat(name, ".cmd");
  575.  
  576.         fname = flook(name, TRUE);
  577.     } else
  578. #if SHARED
  579.     {
  580.         strcpy(tname, pathname[0]);
  581.         fname = flook(tname, TRUE);
  582.     }
  583. #else
  584.         fname = flook(pathname[0], TRUE);
  585. #endif
  586.  
  587.     /* if it isn't around, don't sweat it */
  588.     if (fname == NULL)
  589.         return(TRUE);
  590.  
  591.     /* otherwise, execute the sucker */
  592.     return(dofile(fname));
  593. }
  594.  
  595. /*    Look up the existance of a file along the normal or PATH
  596.     environment variable.
  597.  
  598.     LOOKUP ORDER:
  599.  
  600.         if contains path:
  601.  
  602.             absolute
  603.  
  604.         else
  605.  
  606.             HOME environment directory
  607.             all directories along PATH environment
  608.             directories in table from EPATH.H
  609. */
  610.  
  611. char *PASCAL NEAR flook(fname, hflag)
  612.  
  613. char *fname;    /* base file name to search for */
  614. int hflag;    /* Look in the HOME environment variable first? */
  615.  
  616. {
  617.     register char *home;    /* path to home directory */
  618.     register char *path;    /* environmental PATH variable */
  619.     register char *sp;    /* pointer into path spec */
  620.     register int i;     /* index */
  621.     static char fspec[NFILEN];    /* full path spec to search */
  622.     char *getenv();
  623.  
  624.     /* if we have an absolute path.. check only there! */
  625.     sp = fname;
  626.     while (*sp) {
  627.         if (*sp == ':' || *sp == '\\' || *sp == '/') {
  628.             if (ffropen(fname) == FIOSUC) {
  629.                 ffclose();
  630.                 return(fname);
  631.             } else
  632.                 return(NULL);
  633.         }
  634.         ++sp;
  635.     }
  636.  
  637. #if    ENVFUNC
  638.  
  639.     if (hflag) {
  640. #if WMCS
  641.         home = getenv("SYS$HOME");
  642. #else
  643.         home = getenv("HOME");
  644. #endif
  645.         if (home != NULL) {
  646.             /* build home dir file spec */
  647.             strcpy(fspec, home);
  648. #if WMCS
  649.             strcat(fspec,fname);
  650. #else
  651.             strcat(fspec, DIRSEPSTR);
  652.             strcat(fspec, fname);
  653. #endif
  654.  
  655.             /* and try it out */
  656.             if (ffropen(fspec) == FIOSUC) {
  657.                 ffclose();
  658.                 return(fspec);
  659.             }
  660.         }
  661.     }
  662. #endif
  663.  
  664.     /* current directory now overides everything except HOME var */
  665.     if (ffropen(fname) == FIOSUC) {
  666.         ffclose();
  667.         return(fname);
  668.     }
  669.  
  670. #if    ENVFUNC
  671.     /* get the PATH variable */
  672. #if WMCS
  673.     path = getenv("OPT$PATH");
  674. #else
  675. #if OS2
  676.     path = getenv("DPATH");
  677. #else
  678.     path = getenv("PATH");
  679. #endif
  680. #endif
  681.     if (path != NULL)
  682.         while (*path) {
  683.  
  684.             /* build next possible file spec */
  685.             sp = fspec;
  686. #if    TOS
  687.             while (*path && (*path != PATHCHR) && (*path != ','))
  688. #else
  689.             while (*path && (*path != PATHCHR))
  690. #endif
  691.                 *sp++ = *path++;
  692.  
  693.             /* add a terminating dir separator if we need it */
  694.             if ((sp != fspec) && (*(sp-1) != DIRSEPCHAR))
  695.                 *sp++ = DIRSEPCHAR;
  696.             *sp = 0;
  697.             strcat(fspec, fname);
  698.  
  699.             /* and try it out */
  700.             if (ffropen(fspec) == FIOSUC) {
  701.                 ffclose();
  702.                 return(fspec);
  703.             }
  704.  
  705. #if    TOS && MWC
  706.             if ((*path == PATHCHR) || (*path == ','))
  707. #else
  708.             if (*path == PATHCHR)
  709. #endif
  710.                 ++path;
  711.         }
  712. #endif
  713.  
  714.     /* look it up via the old table method */
  715.     for (i=2; i < NPNAMES; i++) {
  716.         strcpy(fspec, pathname[i]);
  717.         strcat(fspec, fname);
  718.  
  719.         /* and try it out */
  720.         if (ffropen(fspec) == FIOSUC) {
  721.             ffclose();
  722.             return(fspec);
  723.         }
  724.     }
  725.  
  726.     return(NULL);    /* no such luck */
  727. }
  728.  
  729. /* Change a key command to a string we can print out.
  730.  * Return the string passed in.
  731.  */
  732. char *PASCAL NEAR cmdstr(c, seq)
  733.  
  734. int c;        /* sequence to translate */
  735. char *seq;    /* destination string for sequence */
  736.  
  737. {
  738.     char *ptr;    /* pointer into current position in sequence */
  739.  
  740.     ptr = seq;
  741.  
  742.     /* apply ^X sequence if needed */
  743.     if (c & CTLX) {
  744.         *ptr++ = '^';
  745.         *ptr++ = 'X';
  746.     }
  747.  
  748.     /* apply ALT key sequence if needed */
  749.     if (c & ALTD) {
  750.         *ptr++ = 'A';
  751.         *ptr++ = '-';
  752.     }
  753.  
  754.     /* apply Shifted sequence if needed */
  755.     if (c & SHFT) {
  756.         *ptr++ = 'S';
  757.         *ptr++ = '-';
  758.     }
  759.  
  760.     /* apply MOUS sequence if needed */
  761.     if (c & MOUS) {
  762.         *ptr++ = 'M';
  763.         *ptr++ = 'S';
  764.     }
  765.  
  766.     /* apply meta sequence if needed */
  767.     if (c & META) {
  768.         *ptr++ = 'M';
  769.         *ptr++ = '-';
  770.     }
  771.  
  772.     /* apply SPEC sequence if needed */
  773.     if (c & SPEC) {
  774.         *ptr++ = 'F';
  775.         *ptr++ = 'N';
  776.     }
  777.  
  778.     /* apply control sequence if needed */
  779.     if (c & CTRL) {
  780.  
  781.         /* non normal spaces look like @ */
  782.         if (ptr == seq && ((c & 255) == ' '))
  783.             c = '@';
  784.  
  785.         *ptr++ = '^';
  786.     }
  787.  
  788.     c = c & 255;    /* strip the prefixes */
  789.  
  790.     /* and output the final sequence */
  791.     *ptr++ = c;
  792.     *ptr = 0;    /* terminate the string */
  793.     return (seq);
  794. }
  795.  
  796. /*    This function looks a key binding up in the binding table    */
  797.  
  798. KEYTAB *getbind(c)
  799.  
  800. register int c;    /* key to find what is bound to it */
  801.  
  802. {
  803.     register KEYTAB *ktp;
  804.  
  805.     /* scan through the binding table, looking for the key's entry */
  806.     ktp = &keytab[0];
  807.     while (ktp->k_type != BINDNUL) {
  808.         if (ktp->k_code == c)
  809.             return(ktp);
  810.         ++ktp;
  811.     }
  812.  
  813.     /* no such binding */
  814.     return((KEYTAB *)NULL);
  815. }
  816.  
  817. /* getfname:    This function takes a ptr to KEYTAB entry and gets the name
  818.         associated with it
  819. */
  820.  
  821. char *PASCAL NEAR getfname(key)
  822.  
  823. KEYTAB *key;    /* key binding to return a name of */
  824.  
  825. {
  826.     int (PASCAL NEAR *func)(); /* ptr to the requested function */
  827.     register NBIND *nptr;    /* pointer into the name binding table */
  828.     register BUFFER *bp;    /* ptr to buffer to test */
  829.     register BUFFER *kbuf;    /* ptr to requested buffer */
  830.  
  831.     /* if this isn't a valid key, it has no name */
  832.     if (key == NULL)
  833.         return(NULL);
  834.  
  835.     /* skim through the binding table, looking for a match */
  836.     if (key->k_type == BINDFNC) {
  837.         func = key->k_ptr.fp;
  838.         nptr = &names[0];
  839.         while (nptr->n_func != NULL) {
  840.             if (nptr->n_func == func)
  841.                 return(nptr->n_name);
  842.             ++nptr;
  843.         }
  844.         return(NULL);
  845.     }
  846.  
  847.     /* skim through the buffer list looking for a match */
  848.     if (key->k_type == BINDBUF) {
  849.         kbuf = key->k_ptr.buf;
  850.         bp = bheadp;
  851.         while (bp) {
  852.             if (bp == kbuf)
  853.                 return(bp->b_bname);
  854.             bp = bp->b_bufp;
  855.         }
  856.         return(NULL);
  857.     }
  858.     return(NULL);
  859. }
  860.  
  861. /* fncmatch:    match fname to a function in the names table and return
  862.         any match or NULL if none */
  863.  
  864. #if    MSC
  865. int (PASCAL NEAR *PASCAL NEAR fncmatch(char *fname))(void)
  866. #else
  867. int (PASCAL NEAR *PASCAL NEAR fncmatch(fname))()
  868.  
  869. char *fname;    /* name to attempt to match */
  870. #endif
  871.  
  872. {
  873.     int nval;
  874.  
  875.     if ((nval = binary(fname, namval, numfunc)) == -1)
  876.         return(NULL);
  877.     else
  878.         return(names[nval].n_func);
  879. }
  880.  
  881. char *PASCAL NEAR namval(index)
  882.  
  883. int index;    /* index of name to fetch out of the name table */
  884.  
  885. {
  886.     return(names[index].n_name);
  887. }
  888.  
  889. /*    stock()     String key name TO Command Key
  890.  
  891.     A key binding consists of one or more prefix functions followed by
  892.     a keystroke.  Allowable prefixes must be in the following order:
  893.  
  894.     ^X    preceeding control-X
  895.     A-    similtaneous ALT key (on PCs mainly)
  896.     S-    shifted function key
  897.     MS    mouse generated keystroke
  898.     M-    Preceding META key
  899.     FN    function key
  900.     ^    control key
  901.  
  902.     Meta and ^X prefix of lower case letters are converted to upper
  903.     case.  Real control characters are automatically converted to
  904.     the ^A form.
  905. */
  906.  
  907. unsigned int PASCAL NEAR stock(keyname)
  908.  
  909. char *keyname;    /* name of key to translate to Command key form */
  910.  
  911. {
  912.     register unsigned int c;    /* key sequence to return */
  913.  
  914.     /* parse it up */
  915.     c = 0;
  916.  
  917.     /* Do ^X prefix */
  918.     if(*keyname == '^' && *(keyname+1) == 'X') {
  919.         if(*(keyname+2) != 0) { /* Key is not bare ^X */
  920.             c |= CTLX;
  921.             keyname += 2;
  922.         }
  923.     }
  924.  
  925.     /* and the ALT key prefix */
  926.     if (*keyname == 'A' && *(keyname+1) == '-') {
  927.         c |= ALTD;
  928.         keyname += 2;
  929.     }
  930.  
  931.     /* and the SHIFTED prefix */
  932.     if (*keyname == 'S' && *(keyname+1) == '-') {
  933.         c |= SHFT;
  934.         keyname += 2;
  935.     }
  936.  
  937.     /* and the mouse (MOUS) prefix */
  938.     if (*keyname == 'M' && *(keyname+1) == 'S') {
  939.         c |= MOUS;
  940.         keyname += 2;
  941.     }
  942.  
  943.     /* then the META prefix */
  944.     if (*keyname == 'M' && *(keyname+1) == '-') {
  945.         c |= META;
  946.         keyname += 2;
  947.     }
  948.  
  949.     /* next the function prefix */
  950.     if (*keyname == 'F' && *(keyname+1) == 'N') {
  951.         c |= SPEC;
  952.         keyname += 2;
  953.     }
  954.  
  955.     /* a control char?  (NOT Always upper case anymore) */
  956.     if (*keyname == '^' && *(keyname+1) != 0) {
  957.         c |= CTRL;
  958.         ++keyname;
  959.         if (*keyname == '@')
  960.             *keyname = ' ';
  961.     }
  962.  
  963.     /* A literal control character? (Boo, hiss) */
  964.     if (*keyname < 32) {
  965.         c |= CTRL;
  966.         *keyname += '@';
  967.     }
  968.  
  969.     /* make sure we are not lower case if used with ^X or M- */
  970.     if(!(c & (MOUS|SPEC|ALTD|SHFT)))    /* If not a special key */
  971.         if( c & (CTLX|META))        /* If is a prefix */
  972.         uppercase((unsigned char *)keyname);        /* Then make sure it's upper case */
  973.  
  974.     /* the final sequence... */
  975.     c |= *keyname;
  976.     return(c);
  977. }
  978.  
  979. char *PASCAL NEAR transbind(skey)    /* string key name to binding name.... */
  980.  
  981. char *skey;    /* name of key to get binding for */
  982.  
  983. {
  984.     char *bindname;
  985.  
  986.     bindname = getfname(getbind(stock(skey)));
  987.     if (bindname == NULL)
  988.         bindname = errorm;
  989.  
  990.     return(bindname);
  991. }
  992.  
  993. int PASCAL NEAR execkey(key, f, n)    /* execute a function bound to a key */
  994.  
  995. KEYTAB *key;    /* key to execute */
  996. int f, n;    /* agruments to C function */
  997.  
  998. {
  999.     register int status;    /* error return */
  1000.  
  1001.     if (key->k_type == BINDFNC)
  1002.         return((*(key->k_ptr.fp))(f, n));
  1003.     if (key->k_type == BINDBUF) {
  1004.         while (n--) {
  1005.             status = dobuf(key->k_ptr.buf);
  1006.             if (status != TRUE)
  1007.                 return(status);
  1008.         }
  1009.     }
  1010.     return(TRUE);
  1011. }
  1012.  
  1013. /* set a KEYTAB to the given name of the given type */
  1014.  
  1015. #if    PROTO
  1016. int setkey(KEYTAB *key, char *name)
  1017. #else
  1018. setkey(key, name)
  1019.  
  1020. KEYTAB *key;        /* ptr to key to set */
  1021. char *name;        /* name of function or buffer */
  1022. #endif
  1023. {
  1024.     int (PASCAL NEAR *ktemp)();    /* temp function pointer to assign */
  1025.     register BUFFER *kmacro;    /* ptr to buffer of macro to bind to key */
  1026.     char bufn[NBUFN];        /* buffer to hold macro name */
  1027.  
  1028.     /* are we unbinding it? */
  1029.     if (*name == 0) {
  1030.         key->k_type = BINDNUL;
  1031.         return(TRUE);
  1032.     }
  1033.  
  1034.     /* bind to a built in function? */
  1035.     if ((ktemp = fncmatch(name)) != NULL) {
  1036.         key->k_ptr.fp = ktemp;
  1037.         key->k_type = BINDFNC;
  1038.         return(TRUE);
  1039.     }
  1040.  
  1041.     /* is it a procedure/macro? */
  1042.     strcpy(bufn, "[");
  1043.     strcat(bufn, name);
  1044.     strcat(bufn, "]");
  1045.     if ((kmacro=bfind(bufn, FALSE, 0)) != NULL) {
  1046.         key->k_ptr.buf = kmacro;
  1047.         key->k_type = BINDBUF;
  1048.         return(TRUE);
  1049.     }
  1050.  
  1051.     /* not anything we can bind to */
  1052.     mlwrite(TEXT16);
  1053. /*        "[No such function]" */
  1054.     return(FALSE);
  1055. }
  1056.  
  1057.